##################################################################################
##                                                                              ##
##  This file is part of the buola project (https://code.google.com/p/buola/).  ##
##                                                                              ##
##  Copyright(c) 2007-2012 Xavi Gratal                                          ##
##  gratal AT gmail DOT com                                                     ##
##                                                                              ##
##  Buola is free software: you can redistribute it and/or modify               ##
##  it under the terms of the GNU General Public License as published by        ##
##  the Free Software Foundation, either version 3 of the License, or           ##
##  (at your option) any later version.                                         ##
##                                                                              ##
##  Buola is distributed in the hope that it will be useful,                    ##
##  but WITHOUT ANY WARRANTY; without even the implied warranty of              ##
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               ##
##  GNU General Public License for more details.                                ##
##                                                                              ##
##  You should have received a copy of the GNU General Public License           ##
##  along with buola.  If not, see <http://www.gnu.org/licenses/>.              ##
##                                                                              ##
##################################################################################

##################################################################################
## buola_get_padding(SOURCE_STR TARGET_LEN PADDING_CHAR PADDING_VAR)
##
## returns a padding string
##

macro(buola_get_padding SOURCE_STR TARGET_LEN PADDING_CHAR PADDING_VAR)
    string(LENGTH "${SOURCE_STR}" source_len)
    math(EXPR padding "${TARGET_LEN}-${source_len}")
    string(RANDOM LENGTH ${padding} ALPHABET "${PADDING_CHAR}" ${PADDING_VAR})
endmacro()

##################################################################################
## buola_print_pair(LEFT_PART RIGHT_PART)
##
## prints an information line, aligning both left and right part to fixed width
##

function(buola_print_pair LEFT_PART RIGHT_PART)
    math(EXPR right_size "${BUOLA_TERM_COLUMNS}-40")
    set(left_text "      ${LEFT_PART}")
    set(right_rest "${RIGHT_PART}")
    while(NOT "${right_rest}" STREQUAL "")
        string(LENGTH "${right_rest}" right_len)
        if(right_len GREATER right_size)
            string(SUBSTRING "${right_rest}" 0 ${right_size} right_current)
            string(SUBSTRING "${right_rest}" ${right_size} -1 right_rest)
        else()
            set(right_current "${right_rest}")
            set(right_rest "")
        endif()
    
        buola_get_padding("${left_text}" 40 " " padding_str)
        message("${left_text}${padding_str}${right_current}")
        set(left_text "")
    endwhile()
endfunction()

##################################################################################
## buola_print_header(HEADER_TEXT)
##
## prints a header
##

function(buola_print_header HEADER_TEXT)
    if("${HEADER_TEXT}" STREQUAL "")
        set(REAL_TEXT "")
    else()
        set(REAL_TEXT "--- ${HEADER_TEXT} ")
    endif()

    buola_get_padding("${REAL_TEXT}" ${BUOLA_TERM_COLUMNS} "-" padding_str)
    message("${REAL_TEXT}${padding_str}")
endfunction()

##################################################################################
## buola_print_cpp_info()
##
## prints information about the C++ flags and the type of build
##

macro(buola_print_cpp_info)
    string(TOUPPER ${CMAKE_BUILD_TYPE} UPPERCASE_BUILD_TYPE)

    buola_print_pair("C++ Compiler:" "${CMAKE_CXX_COMPILER}")
    buola_print_pair("Build type:" "${CMAKE_BUILD_TYPE}")
    buola_print_pair("C++ flags:" "${CMAKE_CXX_FLAGS}")

    if(UPPERCASE_BUILD_TYPE STREQUAL "RELEASE")
        buola_print_pair("C++ flags: (Release)" "${CMAKE_CXX_FLAGS_RELEASE}")
    elseif(UPPERCASE_BUILD_TYPE STREQUAL "DEBUG")
        buola_print_pair("C++ flags: (Debug)" "${CMAKE_CXX_FLAGS_DEBUG}")
    elseif(UPPERCASE_BUILD_TYPE STREQUAL "RELWITHDEBINFO")
        buola_print_pair("C++ flags: (Debuggable release)" "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
    elseif(UPPERCASE_BUILD_TYPE STREQUAL "MINSIZEREL")
        buola_print_pair("C++ flags: (Minimum size)" "${CMAKE_CXX_FLAGS_MINSIZEREL}")
    endif()
endmacro()

##################################################################################
## buola_print_install_info()
##
## prints information about the installation prefix
##

macro(buola_print_install_info)
    buola_print_pair("Installation prefix:" "${CMAKE_INSTALL_PREFIX}")
endmacro()

##################################################################################
## buola_add_option(OPTION_VAR DESCRIPTION DEFAULT_VALUE GROUP)
##
## adds a buola option
##

macro(buola_add_option OPTION_VAR DESCRIPTION DEFAULT_VALUE GROUP)
    option(${OPTION_VAR} "${DESCRIPTION}?" "${DEFAULT_VALUE}")
    list(APPEND BUOLA_OPTION_LIST_NAME "${OPTION_VAR}")
    list(APPEND BUOLA_OPTION_LIST_DESCRIPTION "${DESCRIPTION}")
    list(APPEND BUOLA_OPTION_LIST_GROUP "${GROUP}")
    list(APPEND BUOLA_OPTION_GROUPS "${GROUP}")
    list(REMOVE_DUPLICATES BUOLA_OPTION_GROUPS)
endmacro()

##################################################################################
## buola_print_option_info()
##
## prints information about the optional libraries
##

macro(buola_print_option_info)
    foreach(group ${BUOLA_OPTION_GROUPS})
        list(LENGTH BUOLA_OPTION_LIST_NAME num)
        math(EXPR realnum "${num}-1")
        foreach(i RANGE ${realnum})
            list(GET BUOLA_OPTION_LIST_GROUP ${i} g)
            if(g STREQUAL group)
                list(GET BUOLA_OPTION_LIST_NAME ${i} n)
                list(GET BUOLA_OPTION_LIST_DESCRIPTION ${i} d)
                buola_print_pair("${d}:" "${${n}}")
            endif()
        endforeach()
        message("")
    endforeach()
endmacro()

##################################################################################
## buola_find_optional_libraries(LIB_VAR HAVE_VAR libraries...)
##
## adds an optional library that buola will look for
##

macro(buola_find_optional_libraries LIB_VAR HAVE_VAR)
    set(${HAVE_VAR} "YES")
    foreach(i ${ARGN})
        find_library(new_optional_lib-${i} ${i})
        if(new_optional_lib-${i})
            if(${HAVE_VAR})
                list(APPEND ${LIB_VAR} ${new_optional_lib-${i}})
            endif()
        else()
            if(${HAVE_VAR})
                set(${LIB_VAR} ${LIB_VAR}-NOTFOUND)
                set(${HAVE_VAR} "NO")
            endif()
            list(APPEND BUOLA_OPTIONAL_LIBRARY_MISSING ${i})
        endif()
    endforeach()
endmacro()

##################################################################################
## buola_find_libraries(LIB_VAR libraries...)
##
## adds an optional library that buola will look for
##

macro(buola_find_libraries LIB_VAR)
    set(have_required_lib "YES")
    foreach(i ${ARGN})
        find_library(new_required_lib-${i} ${i})
        if(new_required_lib-${i})
            if(have_required_lib)
                list(APPEND ${LIB_VAR} ${new_required_lib-${i}})
            endif()
        else()
            if(${HAVE_VAR})
                set(${LIB_VAR} ${LIB_VAR}-NOTFOUND)
                set(have_required_lib "NO")
            endif()
            list(APPEND BUOLA_REQUIRED_LIBRARY_MISSING ${i})
        endif()
    endforeach()
endmacro()

##################################################################################
## buola_find_optional_packages(HAVE_VAR packages...)
##
## adds an optional library that buola will look for
##

macro(buola_find_optional_packages HAVE_VAR)
    set(${HAVE_VAR} "YES")
    foreach(i ${ARGN})
        string(TOUPPER ${i} i_upper)
        find_package(${i} QUIET)
        if(NOT ${i_upper}_FOUND)
            set(${HAVE_VAR} "NO")
            list(APPEND BUOLA_OPTIONAL_LIBRARY_MISSING ${i})
        endif()
    endforeach()
endmacro()

##################################################################################
## buola_print_optional_libraries_info()
##
## prints information about the optional libraries
##

macro(buola_print_optional_libraries_info)
    if(BUOLA_OPTIONAL_LIBRARY_MISSING)
        message("      The following optional libraries were NOT found:")
        foreach(i ${BUOLA_OPTIONAL_LIBRARY_MISSING})
            message("          ${i}")
        endforeach(i)
        message("")
    endif()
endmacro()

##################################################################################
## buola_print_all_info()
##
## prints build information for the project
##

macro(buola_print_all_info)
    message("")
    buola_print_header("Build information for ${CMAKE_PROJECT_NAME}")
    message("")
    buola_print_cpp_info()  
    message("")
    buola_print_install_info()
    message("")
    buola_print_option_info()
    buola_print_optional_libraries_info()
    buola_print_header("")
    message("")
endmacro()

##################################################################################
## buola_create_examples("SOURCE_FILES" "LINK_LIBRARIES")
##
## creates example executables for a list of source files
##
## always pass arguments as a stringified list "${LIST}"
##

macro(buola_create_examples SOURCE_FILES LIBRARIES)
    foreach(SOURCE_FILE ${SOURCE_FILES})
        get_filename_component(SOURCE_NAME ${SOURCE_FILE} NAME_WE)
        get_filename_component(SOURCE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME)
        add_executable("example_${SOURCE_FOLDER}_${SOURCE_NAME}" ${SOURCE_FILE})
        target_link_libraries("example_${SOURCE_FOLDER}_${SOURCE_NAME}" ${LIBRARIES})
        install(TARGETS "example_${SOURCE_FOLDER}_${SOURCE_NAME}" DESTINATION ${BIN_INSTALL_DIR})
    endforeach()
endmacro()

##################################################################################
## buola_create_tests("SOURCE_FILES" "LINK_LIBRARIES")
##
## creates test executables for a list of source files and adds tests
##
## always pass arguments as a stringified list "${LIST}"
##

macro(buola_create_tests SOURCE_FILES LIBRARIES)
    foreach(SOURCE_FILE ${SOURCE_FILES})
        get_filename_component(SOURCE_NAME ${SOURCE_FILE} NAME_WE)
        get_filename_component(SOURCE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME)
        add_executable("test_${SOURCE_FOLDER}_${SOURCE_NAME}" ${SOURCE_FILE})
        target_link_libraries("test_${SOURCE_FOLDER}_${SOURCE_NAME}" ${LIBRARIES})
        add_test("${SOURCE_FOLDER}_${SOURCE_NAME}" "test_${SOURCE_FOLDER}_${SOURCE_NAME}")
    endforeach()
endmacro()

macro(buola_add_service_files SERVICE_FILES)
    foreach(SERVICE_FILE ${SERVICE_FILES})
        configure_file(${SERVICE_FILE} ${SERVICE_FILE})
        install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SERVICE_FILE} DESTINATION ${SHARE_INSTALL_DIR}/dbus-1/services)
    endforeach()
endmacro()

macro(buola_add_application_files SERVICE_FILES)
    foreach(SERVICE_FILE ${SERVICE_FILES})
        configure_file(${SERVICE_FILE} ${SERVICE_FILE})
        install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SERVICE_FILE} DESTINATION ${SHARE_INSTALL_DIR}/applications)
    endforeach()
endmacro()

